/*
    simplecookbook  -  simplecookbook.impressao.PrintPDF.java
                             -------------------
    begin                : 08/10/2008
    copyright            : (C) 2008 by cristovao
    email                : cristovao.wollieson@gmail.com
 ***************************************************************************/

/*
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful, but   *
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 *   General Public License for more details.                              *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,   *
 *   MA  02111-1307 USA                                                    *
 ***************************************************************************/

/**
 * Pacote responsavel pela impressao de material impresso, ou de arquivos
 * que serao impressos em graficas
 * 
 * @author cristovao
 */
package org.ybacoby.simplecookbook.impressao;

import java.awt.Color;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.ArrayList;

import org.ybacoby.simplecookbook.exception.SimpleCookBookException;
import org.ybacoby.simplecookbook.receitas.Receitas;


import com.lowagie.text.ChapterAutoNumber;
import com.lowagie.text.Chunk;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.ExceptionConverter;
import com.lowagie.text.Font;
import com.lowagie.text.Image;
import com.lowagie.text.PageSize;
import com.lowagie.text.Paragraph;
import com.lowagie.text.Phrase;
import com.lowagie.text.Rectangle;
import com.lowagie.text.Section;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfGState;
import com.lowagie.text.pdf.PdfPTable;
import com.lowagie.text.pdf.PdfPageEventHelper;
import com.lowagie.text.pdf.PdfTemplate;
import com.lowagie.text.pdf.PdfWriter;


/**
 * Classe que imprime em arquivos pdfs
 * 
 * @author cristovao
 * 
 */
public class PrintPDF implements IPrintBook {

	/** An Image that goes in the header. */
	public Image headerImage;

	/** The headertable. */
	public PdfPTable table;

	/** The Graphic state */
	public PdfGState gstate;

	/** A template that will hold the total number of pages. */
	public PdfTemplate tpl;

	/** The font that will be used. */
	public BaseFont helv;

	/**
	 * Serve para iniciar o desenvolvimento do documento
	 */
	private Document documento;

	/**
	 * O titulo do livro
	 */
	private String titulo;

	/**
	 * O Autor da obra
	 */
	private String autor;

	/**
	 * Logomarca da aplicacao
	 */
	private String logo;

	/**
	 * Para escrever no documento
	 */
	private PdfWriter writer;

	/**
	 * @see org.ybacoby.simplecookbook.impressao.IPrintBook#addReceita(java.util.ArrayList)
	 */
	public void addReceita(ArrayList<Receitas> receita)
			throws SimpleCookBookException {
		
		for (int i = 0; i < receita.size(); i++) {
			/* Definindo o nome do captulo e seu numero
			 * lembrando que tudo devera ser trabalhado em cima
			 * dos captulos ao inves do documento, neste caso
			 * todos os dados serao adicionados dentro deste capitulo
			 * chamado de receitas
			 */
			ChapterAutoNumber cprReceitas = new ChapterAutoNumber(receita.get(i).getNome());
			
			// Adicionando a tabela com os dados inicias da receita
			PdfPTable ptbReceita = new PdfPTable(4);
			ptbReceita.getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT);
			ptbReceita.getDefaultCell().setBorderWidth(0);
			
			// Criando e adicionando celulas
			Phrase paeReceita = new Phrase();
			Chunk cnkReceita = new Chunk("Tempo de Preparo", new Font(Font.TIMES_ROMAN, 10, Font.BOLDITALIC, Color.black));
			paeReceita.add(cnkReceita);
			ptbReceita.addCell(paeReceita);
			
			paeReceita = new Phrase();
			cnkReceita = new Chunk("Porcoes", new Font(Font.TIMES_ROMAN, 10, Font.BOLDITALIC, Color.black));
			paeReceita.add(cnkReceita);
			ptbReceita.addCell(paeReceita);
			
			paeReceita = new Phrase();
			cnkReceita = new Chunk("Quantidade de Pessoas", new Font(Font.TIMES_ROMAN, 10, Font.BOLDITALIC, Color.black));
			paeReceita.add(cnkReceita);
			ptbReceita.addCell(paeReceita);
			
			paeReceita = new Phrase();
			cnkReceita = new Chunk("Nota", new Font(Font.TIMES_ROMAN, 10, Font.BOLDITALIC, Color.black));
			paeReceita.add(cnkReceita);
			ptbReceita.addCell(paeReceita);
			ptbReceita.completeRow();
			
			paeReceita = new Phrase();
			cnkReceita = new Chunk(receita.get(i).getTempoPreparo(), new Font(Font.TIMES_ROMAN, 10, Font.BOLDITALIC, Color.black));
			paeReceita.add(cnkReceita);
			ptbReceita.addCell(paeReceita);
			
			paeReceita = new Phrase();
			cnkReceita = new Chunk(receita.get(i).getPorcoes(), new Font(Font.TIMES_ROMAN, 10, Font.BOLDITALIC, Color.black));
			paeReceita.add(cnkReceita);
			ptbReceita.addCell(paeReceita);
			
			paeReceita = new Phrase();
			cnkReceita = new Chunk(receita.get(i).getQtdPessoas(), new Font(Font.TIMES_ROMAN, 10, Font.BOLDITALIC, Color.black));
			paeReceita.add(cnkReceita);
			ptbReceita.addCell(paeReceita);
			
			paeReceita = new Phrase();
			cnkReceita = new Chunk(receita.get(i).getNota(), new Font(Font.TIMES_ROMAN, 10, Font.BOLDITALIC, Color.black));
			paeReceita.add(cnkReceita);
			ptbReceita.addCell(paeReceita);
			
			cprReceitas.add(ptbReceita);
			
			/* preparando a sessao de ingredientes
			 * no caso o tipo Section nao possui constructor
			 * necessitando do uso de um dos metodos do
			 * cprReceitas para retornar um objeto do
			 * tipo Section, apos isso sera somente
			 * trabalhado em cima do objeto Section
			 */
			//cprReceitas.addSection("Ingredientes");
			Section stnIngredientes = cprReceitas.addSection("Ingredientes");
			stnIngredientes.add(new Paragraph(" "));
			
			// Preparando a tabela de ingredientes
			PdfPTable ptbIngredientes = new PdfPTable(2);
			ptbIngredientes.getDefaultCell().setHorizontalAlignment(Element.ALIGN_JUSTIFIED);
			
			// Definindo o espaco das colunas
			float[] espaco = {640, 300};
			
			// Alterando o espaco das colunas na tabela
			try {
				ptbIngredientes.setWidths(espaco);
			} catch (DocumentException e1) {
				throw new SimpleCookBookException();
			}
			ptbIngredientes.getDefaultCell().setBorderWidth(0);
			
			// Criando e adicionando celulas
			Phrase paeIngrediente = new Phrase();
			Chunk cnkIngrediente = new Chunk("Descricao", new Font(Font.TIMES_ROMAN, 10, Font.BOLDITALIC, Color.black));
			paeIngrediente.add(cnkIngrediente);
			ptbIngredientes.addCell(paeIngrediente);
			
			paeIngrediente = new Phrase();
			cnkIngrediente = new Chunk("Qtd", new Font(Font.TIMES_ROMAN, 10, Font.BOLDITALIC, Color.black));
			paeIngrediente.add(cnkIngrediente);
			ptbIngredientes.addCell(paeIngrediente);
			ptbIngredientes.getDefaultCell().setHorizontalAlignment(Element.ALIGN_JUSTIFIED);
			
			for (int e = 0; e < receita.get(i).getIngredientes().size(); e++) {
				ptbIngredientes.completeRow();
				
				paeIngrediente = new Phrase();
				cnkIngrediente = new Chunk(receita.get(i).getIngredientes().get(e).getDescricao(), new Font(Font.TIMES_ROMAN, 10, Font.BOLDITALIC, Color.black));
				paeIngrediente.add(cnkIngrediente);
				ptbIngredientes.addCell(paeIngrediente);
				
				paeIngrediente = new Phrase();
				cnkIngrediente = new Chunk(receita.get(i).getIngredientes().get(e).getQtd(), new Font(Font.TIMES_ROMAN, 10, Font.BOLDITALIC, Color.black));
				paeIngrediente.add(cnkIngrediente);
				ptbIngredientes.addCell(paeIngrediente);
			}
			
			// Adicionando a tabela de ingredientes na sessao de ingredientes
			stnIngredientes.add(ptbIngredientes);
			stnIngredientes.add(new Paragraph(" "));
			
			// Preparando para escrever a parte de Preparar
			Section stnPreparar = cprReceitas.addSection("Modo de Fazer");
			stnPreparar.add(new Paragraph(" "));
			
			// Colocando o titulo do documento
			Paragraph prhModoDeFazer = new Paragraph(receita.get(i).getPreparo());
			prhModoDeFazer.setAlignment(Element.ALIGN_JUSTIFIED);
			
			// Adicionando o paragrafo
			stnPreparar.add(prhModoDeFazer);
			
			try {
				this.documento.add(cprReceitas);
			} catch (DocumentException e) {
				throw new SimpleCookBookException();
			}
		}

	}

	/**
	 * @see org.ybacoby.simplecookbook.impressao.IPrintBook#closeDocument()
	 */
	public void closeDocument() throws SimpleCookBookException {
		this.documento.close();

	}

	/**
	 * @see org.ybacoby.simplecookbook.impressao.IPrintBook#openDocument(java.lang.String,
	 *      java.lang.String, java.lang.String, java.lang.String)
	 */
	public void openDocument(String autor, String titulo, String salvar,
			String logo) throws SimpleCookBookException {
		// Criando o documento
		this.documento = new Document(PageSize.A4, 50, 50, 100, 72);

		// Atribuindo dados
		this.titulo = titulo;
		this.autor = autor;
		this.logo = logo;

		// Gerando instancia para criar e gravar o documento
		try {
			this.writer = PdfWriter.getInstance(documento,
					new FileOutputStream(salvar+titulo + ".pdf"));
		} catch (FileNotFoundException e) {
			throw new SimpleCookBookException();
		} catch (DocumentException e) {
			throw new SimpleCookBookException();
		}

		// Iniciando o template de documento
		this.writer.setPageEvent(new DocumentDefinitions());

		// Iniciando o acrescimo de dados no documento
		this.documento.open();
		this.documento.addAuthor(this.autor);
		this.documento.addCreationDate();
		this.documento.addTitle(this.titulo);
	}

	/**
	 * @author cristovao
	 * 
	 *         Definindo os eventos que serao usados neste sistema
	 */
	private class DocumentDefinitions extends PdfPageEventHelper {
		@Override
		public void onOpenDocument(PdfWriter arg0, Document arg1) {
			onOpenDocument_PrintPDF(arg0, arg1);
		}

		@Override
		public void onEndPage(PdfWriter arg0, Document arg1) {
			onEndPage_PrintPDF(arg0, arg1);
		}

		@Override
		public void onCloseDocument(PdfWriter arg0, Document arg1) {
			onCloseDocument_PrintPDF(arg0, arg1);
		}
	}

	/**
	 * Evento que define o formato do documento quando esta sendo criado
	 * 
	 * @param arg0
	 * @param arg1
	 */
	protected void onOpenDocument_PrintPDF(PdfWriter arg0, Document arg1) {
		try {
			// initialization of the header table
			headerImage = Image.getInstance(this.logo);
			
			table = new PdfPTable(2);
			Phrase p = new Phrase();
			Chunk ck = new Chunk(this.titulo + "\n", new Font(Font.TIMES_ROMAN,
					16, Font.BOLDITALIC, Color.blue));
			p.add(ck);
//			ck = new Chunk(this.autor, new Font(Font.HELVETICA, 12,
//					Font.NORMAL, Color.darkGray));
//			p.add(ck);
			//table.getDefaultCell().setBackgroundColor(Color.yellow);
			table.getDefaultCell().setBorderWidth(0);
			table.addCell(p);
			p = new Phrase();
			ck = new Chunk(this.autor, new Font(Font.HELVETICA, 12,
					Font.NORMAL, Color.darkGray));
			p.add(ck);
			table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT);
			table.addCell(p);
			//table.addCell(new Phrase(new Chunk(headerImage, 0, 0)));
			// initialization of the Graphic State
			gstate = new PdfGState();
			gstate.setFillOpacity(0.3f);
			gstate.setStrokeOpacity(0.3f);
			// initialization of the template
			tpl = writer.getDirectContent().createTemplate(100, 100);
			tpl.setBoundingBox(new Rectangle(-20, -20, 100, 100));
			// initialization of the font
			helv = BaseFont.createFont("Helvetica", BaseFont.WINANSI, false);
		} catch (Exception e) {
			throw new ExceptionConverter(e);
		}
	}

	/**
	 * Definindo o comportamento do rodape da pagina
	 * 
	 * @param arg0
	 * @param arg1
	 */
	protected void onEndPage_PrintPDF(PdfWriter arg0, Document arg1) {
		PdfContentByte cb = this.writer.getDirectContent();
		cb.saveState();
		// write the headertable
		table.setTotalWidth(this.documento.right() - this.documento.left());
		table.writeSelectedRows(0, -1, this.documento.left(), this.documento
				.getPageSize().getHeight() - 50, cb);
		// compose the footer
		String text = "Pagina " + writer.getPageNumber() + " de ";
		float textSize = helv.getWidthPoint(text, 12);
		float textBase = this.documento.bottom() - 20;
		cb.beginText();
		cb.setFontAndSize(helv, 12);
		// for odd pagenumbers, show the footer at the left
		if ((writer.getPageNumber() & 1) == 1) {
			cb.setTextMatrix(this.documento.left(), textBase);
			cb.showText(text);
			cb.endText();
			cb.addTemplate(tpl, this.documento.left() + textSize, textBase);
		}
		// for even numbers, show the footer at the right
		else {
			float adjust = helv.getWidthPoint("0", 12);
			cb.setTextMatrix(this.documento.right() - textSize - adjust,
					textBase);
			cb.showText(text);
			cb.endText();
			cb.addTemplate(tpl, this.documento.right() - adjust, textBase);
		}
		cb.saveState();
		// draw a Rectangle around the page
		cb.setColorStroke(Color.orange);
		cb.setLineWidth(2);
		cb.rectangle(20, 20, this.documento.getPageSize().getWidth() - 40,
				this.documento.getPageSize().getHeight() - 40);
		cb.stroke();
		cb.restoreState();
	}

	/**
	 * Definindo detalhes de como sera fechado o documento
	 * 
	 * @param arg0
	 * @param arg1
	 */
	protected void onCloseDocument_PrintPDF(PdfWriter arg0, Document arg1) {
		tpl.beginText();
		tpl.setFontAndSize(helv, 12);
		tpl.setTextMatrix(0, 0);
		tpl.showText(Integer.toString(writer.getPageNumber() - 1));
		tpl.endText();
	}
}
